package org.polyforms.repository.executor.support;

import java.lang.reflect.Method;
import java.util.List;

import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.polyforms.repository.UpdatableRepository;
import org.polyforms.repository.executor.ClassBasedExecutor;
import org.springframework.util.ReflectionUtils;

/**
 * Implementation of {@link UpdatableRepository} which uses JPA as persistence framework.
 * 
 * @author Kuisong Tong
 * @since 1.0
 */
@Named
public final class UpdatableRepositoryExecutor implements ClassBasedExecutor {
    private final JpaRepository jpaRepository = new JpaRepository();

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * {@inheritDoc}
     */
    public Class<?> getMatchedInterface() {
        return UpdatableRepository.class;
    }

    /**
     * {@inheritDoc}
     */
    public Object execute(final Object target, final Method method, final Object... arguments) throws Throwable {
        try {
            return method.invoke(jpaRepository, arguments);
        } catch (final Exception e) {
            ReflectionUtils.handleReflectionException(e);
        }

        throw new IllegalStateException("Should never get here");
    }

    private final class JpaRepository implements UpdatableRepository<Object> {
        /**
         * {@inheritDoc}
         */
        public void add(final Object entity) {
            entityManager.persist(entity);
        }

        /**
         * {@inheritDoc}
         */
        public void remove(final Object entity) {
            if (entity == null) {
                throw new IllegalArgumentException("Parameter entity (Object) must not be null.");
            }
            entityManager.remove(entity);
        }

        /**
         * {@inheritDoc}
         */
        public void remove(final List<Object> entities) {
            if (entities == null) {
                throw new IllegalArgumentException("Parameter entities(List) must not be null.");
            }

            for (final Object entity : entities) {
                remove(entity);
            }
        }
    }
}
